<template>
  <div class="table">
    <table cellspacing="0" cellpadding="0">
      <thead>
      <tr>
        <th v-for="(column, index) in columns" :style= "{'text-align': column.align, 'width': column.width}">
          <label v-if="column.type === 'selection'">
            <input type="checkbox" v-model="checks" @click="handleCheckAll">
          </label>
          <label class="ellipsis" :title="renderHeader(column, index)" v-else>
            {{ renderHeader(column, index) }}
          </label>
        </th>
      </tr>
      </thead>
      <tbody>
      <tr v-if="initItems.length === 0">
        <td :colspan=columns.length style="text-align: center">
          <zz-none content="暂无数据"></zz-none>
        </td>
      </tr>
      <tr v-for="(item, index) in initItems" :key="item.id" v-show="show(item)">
        <td v-for="(column, snum) in columns" :key="column.key" :style= "{'text-align': columns[snum].align}">
          <label v-if="column.type === 'selection'">
            <input type="checkbox" :value="item.id" v-model="checkGroup">
          </label>
          <div v-if="column.type === 'action'">
            <button size="small" class="confirm" @click="RowClick(item,$event,index,action)" v-for='action in (item.handle)'>{{action.text}}</button>
          </div>
          <div class="ellipsis" :title="renderBody(item,column,index)" v-if="column.type === 'normal'">
            {{renderBody(item,column,index)}}
          </div>
          <label class="ellipsis" @click="toggle(index,item)" v-if="!column.type">
            <span>
              <i v-html='item.spaceHtml'></i>
              <i v-if="item.children && item.children.length > 0" class="iconfont pointer"
                 :class="{'icon-triangle-down defaultTreeColor':item.expanded,'icon-triangle-right':!item.expanded}"></i>
              <i v-else class="ms-tree-space"></i>
            </span>
            <span :title="renderBody(item,column,index)">{{renderBody(item,column,index)}}</span>
          </label>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
  export default {
    name: 'treeGrid',
    props: {
      columns: Array,
      items: {
        type: Array,
        default: function () {
          return []
        }
      }
    },
    data () {
      return {
        initItems: [], // 处理后数据数组
        checkGroup: [], //  复选框数组
        checks: false, // 全选
        dataLength: 0 // 树形数据长度
      }
    },
    computed: {
    },
    watch: {
      items () {
        if (this.items) {
          this.dataLength = this.Length(this.items)
          this.initData(this.deepCopy(this.items), 1, null)
          this.checkGroup = this.renderCheck(this.items)
          if (this.checkGroup.length === this.dataLength) {
            this.checks = true
          } else {
            this.checks = false
          }
        }
      },
      checkGroup (data) {
        this.checkAllGroupChange(data)
      }
    },
    mounted () {
      if (this.items) {
        this.dataLength = this.Length(this.items)
        this.initData(this.deepCopy(this.items), 1, null)
        this.checkGroup = this.renderCheck(this.items)
        if (this.checkGroup.length === this.dataLength) {
          this.checks = true
        } else {
          this.checks = false
        }
      }
    },
    methods: {
      // 点击某一行事件
      RowClick (data, event, index, text) {
        console.log(this.initItems[1])
        let result = this.makeData(data)
        this.$emit('on-row-click', result, event, index, text)
      },
      // 点击事件 返回数据处理
      makeData (data) {
        const t = this.type(data)
        let o
        if (t === 'array') {
          o = []
        } else if (t === 'object') {
          o = {}
        } else {
          return data
        }
        if (t === 'array') {
          for (let i = 0; i < data.length; i++) {
            o.push(this.makeData(data[i]))
          }
        } else if (t === 'object') {
          for (let i in data) {
            if (i !== 'spaceHtml' && i !== 'parent' && i !== 'level' && i !== 'expanded' && i !== 'isShow' && i !== 'load') {
              o[i] = this.makeData(data[i])
            }
          }
        }
        return o
      },
      // 数据处理 增加自定义属性监听
      initData (items, level, parent, isClear) {
        if (!isClear) {
          this.initItems = []
        }
        let spaceHtml = ''
        for (var i = 1; i < level; i++) {
          spaceHtml += "<i class='ms-tree-space' style='margin-left: 20px'></i>"
        }
        items.forEach((item, index) => {
          item = Object.assign({}, item, {
            'parent': parent,
            'level': level,
            'spaceHtml': spaceHtml,
            'handle': item.handle
          })
          if (!item.expanded) {
            Object.assign(item, {'expanded': false})
          } else {
            Object.assign(item, {'expanded': true})
          }
          if (item.parent && item.parent.expanded) {
            Object.assign(item, {'isShow': true})
          }
          let sBoolean
          if (item.expanded) {
            sBoolean = true
          } else {
            sBoolean = false
          }
          item = Object.assign({}, item, {
            'load': (sBoolean)
          })
          this.initItems.push(item)
          if (item.children && item.expanded) {
            this.initData(item.children, level + 1, item, true)
          }
        })
        console.log(this.initItems)
      },
      //  隐藏显示
      show (item) {
        return ((item.level === 1) || (item.parent && item.parent.expanded && item.isShow))
      },
      toggle (index, item) {
        let level = item.level + 1
        let spaceHtml = ''
        for (var i = 1; i < level; i++) {
          spaceHtml += "<i class='ms-tree-space' style='margin-left: 20px'></i>"
        }
        if (item.children) {
          if (item.expanded) {
            item.expanded = !item.expanded
            this.close(index, item)
          } else {
            item.expanded = !item.expanded
            if (item.load) {
              this.open(index, item)
            } else {
              item.load = true
              item.children.forEach((child, childIndex) => {
                this.initItems.splice((index + childIndex + 1), 0, child)
                // 设置监听属性
                this.$set(this.initItems[index + childIndex + 1], 'parent', item)
                this.$set(this.initItems[index + childIndex + 1], 'level', level)
                this.$set(this.initItems[index + childIndex + 1], 'spaceHtml', spaceHtml)
                this.$set(this.initItems[index + childIndex + 1], 'isShow', true)
                this.$set(this.initItems[index + childIndex + 1], 'expanded', false)
              })
            }
          }
        }
        console.log(this.initItems)
      },
      open (index, item) {
        if (item.children) {
          item.children.forEach((child, childIndex) => {
            child.isShow = true
            if (child.children && child.expanded) {
              this.open(index + childIndex + 1, child)
            }
          })
        }
      },
      close (index, item) {
        if (item.children) {
          item.children.forEach((child, childIndex) => {
            child.isShow = false
            child.expanded = false
            if (child.children) {
              this.close(index + childIndex + 1, child)
            }
          })
        }
      },
      handleCheckAll () {
        this.checks = !this.checks
        if (this.checks) {
          this.checkGroup = this.getArray(this.checkGroup.concat(this.All(this.items)))
        } else {
          this.checkGroup = []
        }
      },
      // 数组去重
      getArray (a) {
        var hash = {}
        var len = a.length
        var result = []
        for (var i = 0; i < len; i++) {
          if (!hash[a[i]]) {
            hash[a[i]] = true
            result.push(a[i])
          }
        }
        return result
      },
      checkAllGroupChange (data) {
        if (this.dataLength > 0 && data.length === this.dataLength) {
          this.checks = true
        } else {
          this.checks = false
        }
        this.$emit('on-selection-change', this.checkGroup)
      },
      All (data) {
        let arr = []
        data.forEach((item) => {
          arr.push(item.id)
          if (item.children && item.children.length > 0) {
            arr = arr.concat(this.All(item.children))
          }
        })
        return arr
      },
      // 返回树形数据长度
      Length (data) {
        let length = data.length
        data.forEach((child) => {
          if (child.children) {
            length += this.Length(child.children)
          }
        })
        return length
      },
      // 返回表头
      renderHeader (column, $index) {
        if ('renderHeader' in this.columns[$index]) {
          return this.columns[$index].renderHeader(column, $index)
        } else {
          return column.title || ''
        }
      },
      // 返回内容
      renderBody (row, column, index) {
        return row[column.key]
      },
      // 默认选中
      renderCheck (data) {
        let arr = []
        data.forEach((item) => {
          if (item._checked) {
            arr.push(item.id)
          }
          if (item.children && item.children.length > 0) {
            arr = arr.concat(this.renderCheck(item.children))
          }
        })
        return arr
      },
      // 深度拷贝函数
      deepCopy (data) {
        var t = this.type(data)
        var o
        var i
        var ni
        if (t === 'array') {
          o = []
        } else if (t === 'object') {
          o = {}
        } else {
          return data
        }
        if (t === 'array') {
          for (i = 0, ni = data.length; i < ni; i++) {
            o.push(this.deepCopy(data[i]))
          }
          return o
        } else if (t === 'object') {
          for (i in data) {
            o[i] = this.deepCopy(data[i])
          }
          return o
        }
      },
      type (obj) {
        var toString = Object.prototype.toString
        var map = {
          '[object Boolean]': 'boolean',
          '[object Number]': 'number',
          '[object String]': 'string',
          '[object Function]': 'function',
          '[object Array]': 'array',
          '[object Date]': 'date',
          '[object RegExp]': 'regExp',
          '[object Undefined]': 'undefined',
          '[object Null]': 'null',
          '[object Object]': 'object'
        }
        return map[toString.call(obj)]
      }
    }
  }
</script>
<style lang="scss"  scoped>
  .defaultTreeColor{
    color: $color;
  }
  .pointer{
    cursor: pointer;
  }
  .confirm{
    border: none;
    background: none;
    color: $color;
    cursor: pointer;
  }
  .ellipsis{
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
</style>
